using System;
using System.Xml;
using System.Text;
using System.Globalization;

namespace Waymex.Gps
{
	/// <summary>
	/// Collection of Lap objects.
	/// </summary>
	public class LapCollection : System.Collections.IEnumerable
	{
		private const string vbModule = "Laps";
		private const string XML_ROOT = "gpslaps";
		private const string XML_LAP = "gpslap";

		private int m_hashCode = -1;

		private System.Collections.ArrayList mcLaps;
		/// <summary>
		/// This method adds a Lap object to the collection. 
		/// </summary>
		public void Add(Lap lap)
		{

			try
			{
				mcLaps.Add(lap);
			}
			catch (Exception e)
			{
				throw new InvalidDataException(e.Message, e);
			}
		}
		/// <summary>
		/// Returns the number of Lap objects in the collection. 
		/// </summary>
		public int Count
		{
			get
			{
				try
				{
					return mcLaps.Count;
				}
				catch (Exception e)
				{
					throw new InvalidDataException(e.Message, e);
				}
			}
		}

		//default indexer property
		/// <summary>
		/// Can be used to refer to a member of the collection by ordinal reference.
		/// This Property is the default indexer in C#.
		/// </summary>
		public Lap this[int index]
		{
			get
			{
				return (Lap)mcLaps[index];
			}

		}
		/// <summary>
		/// This method is the enumerator for the collection.
		/// </summary>
		public System.Collections.IEnumerator GetEnumerator()
		{
			return mcLaps.GetEnumerator();
		}
		/// <summary>
		/// Constructor for the LapCollection object.
		/// </summary>
		public LapCollection() :  base()
		{
			mcLaps = new System.Collections.ArrayList();
		}
        /// <summary>
        /// Returns an XML representation of the object.
        /// </summary>
        public string ToXml()
        {
            return ToXml(String.Empty);
        }
        /// <summary>
        /// Returns an XML representation of the object.
        /// This overloaded method accepts an xslt filename which can be used to ransform the xml.
        /// </summary>
        public string ToXml(string xsltFilename)
        {
			StringBuilder strbldXML = new StringBuilder("");
            String xml = String.Empty;

			try
			{
				strbldXML.Append ("<");
				strbldXML.Append (XML_ROOT);
				strbldXML.Append (">");

				foreach(Lap objLap in mcLaps)
				{
					strbldXML.Append(objLap.ToXml());
				}

				strbldXML.Append ("</");
				strbldXML.Append (XML_ROOT);
				strbldXML.Append (">");

                //transform if required
                xml = strbldXML.ToString();

                if (xsltFilename.Length > 0)
                {
                    xml = Waymex.Xml.Transform.XsltTransform(xml, xsltFilename);
                }
            }
            catch (NullReferenceException e)
            { 
				throw new XmlException(e.Message, e);

			}
			return xml;
		}

		/// <summary>
		/// This method populates the object from XML.
		/// </summary>
        public void XmlLoad(string xml)
		{

			XmlDocument objDOM = new XmlDocument();

			try
			{
                objDOM.LoadXml(xml);

				if(objDOM.FirstChild.Name == XML_ROOT)
				{
					foreach(XmlNode objNode in objDOM.FirstChild.ChildNodes)
					{
						try
						{
							switch(objNode.Name)
							{
								case XML_LAP:

									Lap objLap = new Lap();
									objLap.XmlLoad(objNode.OuterXml);
									mcLaps.Add(objLap);
									break;
							
							}
						}
						catch(NullReferenceException ex)
						{
						}
					}
				}	
			}
			catch(Exception e)
			{
				throw new XmlException(e.Message, e);
			}
		}
		/// <summary>
		/// This method returns a System.Data.Dataset populated with the contents of the LapCollection object.
		/// The dataset includes one table called 'Laps'.
		/// </summary>
		public System.Data.DataSet ToDataSet()
		{
			//constants for the dataset
			const string DS_LAPS = "Laps";

			//constants for the waypoints table

//		public int StartTime = 0;
//		public int TotalTime = 0;
//		public float TotalDistance = 0;
//		public double BeginLatitude = 0;
//		public double EndLatitude = 0;
//		public double BeginLongitude = 0;
//		public double EndLongitude = 0;
//		public short Calories = 0;
//		public byte TrackIndex = 0;
//		public byte Unused1 = 0;
			
			const string DS_TABLE_LAPS = "Laps";

			const string DS_FIELD_LAPS_START_TIME = "Start Time";
			const string DS_FIELD_LAPS_START_TIME_TYPE = "System.Int32";
			const string DS_FIELD_LAPS_TOTAL_TIME = "Total Time";
			const string DS_FIELD_LAPS_TOTAL_TIME_TYPE = "System.Int32";
			const string DS_FIELD_LAPS_TOTAL_DISTANCE = "Total Distance";
			const string DS_FIELD_LAPS_TOTAL_DISTANCE_TYPE = "System.Single";
			const string DS_FIELD_LAPS_BEGIN_LATITUDE = "Begin Latitude";
			const string DS_FIELD_LAPS_BEGIN_LATITUDE_TYPE = "System.Double";
			const string DS_FIELD_LAPS_END_LATITUDE = "End Latitude";
			const string DS_FIELD_LAPS_END_LATITUDE_TYPE = "System.Double";
			const string DS_FIELD_LAPS_BEGIN_LONGITUDE = "Begin Longitude";
			const string DS_FIELD_LAPS_BEGIN_LONGITUDE_TYPE = "System.Double";
			const string DS_FIELD_LAPS_END_LONGITUDE = "End Longitude";
			const string DS_FIELD_LAPS_END_LONGITUDEE_TYPE = "System.Double";
			const string DS_FIELD_LAPS_CALORIES = "Calories";
			const string DS_FIELD_LAPS_CALORIES_TYPE = "System.Int16";
			const string DS_FIELD_LAPS_TRACK_INDEX = "Track Index";
			const string DS_FIELD_LAPS_TRACK_INDEX_TYPE = "System.Byte";

            const string DS_FIELD_LAPS_INDEX = "Index";
            const string DS_FIELD_LAPS_INDEX_TYPE = "System.Int32";
            const string DS_FIELD_LAPS_AVERAGE_HEART_RATE = "Average Heart Rate";
            const string DS_FIELD_LAPS_AVERAGE_HEART_RATE_TIME_TYPE = "System.Byte";
            const string DS_FIELD_LAPS_MAX_HEART_RATE = "Max Heart Rate";
            const string DS_FIELD_LAPS_MAX_HEART_RATE_TYPE = "System.Byte";
            const string DS_FIELD_LAPS_INTENSITY = "Intensity";
            const string DS_FIELD_LAPS_INTENSITY_TIME_TYPE = "System.Byte";
            const string DS_FIELD_LAPS_AVERAGE_CADENCE = "Average Cadence";
            const string DS_FIELD_LAPS_AVERAGE_CADENCE_TIME_TYPE = "System.Byte";
            const string DS_FIELD_LAPS_TRIGGER_METHOD = "Trigger Method";
            const string DS_FIELD_LAPS_TRIGGER_METHOD_TIME_TYPE = "System.Byte";
            const string DS_FIELD_LAPS_MAX_SPEED = "Max Speed";
            const string DS_FIELD_LAPS_MAX_SPEED_TIME_TYPE = "System.Single";
            
            //const string DS_FIELD_LAPS_UNUSED_1 = "Unused 1";
			//const string DS_FIELD_LAPS_UNUSED_1_TYPE = "System.Byte";

			//create a new data set
			System.Data.DataSet ds = new System.Data.DataSet(DS_LAPS);
            ds.Locale = CultureInfo.InvariantCulture;
			
			//create the waypoints table			
			System.Data.DataTable dtL = new System.Data.DataTable(DS_TABLE_LAPS);
            dtL.Locale = CultureInfo.InvariantCulture;
		
			//add the columns to the waypoints table
			dtL.Columns.Add(DS_FIELD_LAPS_START_TIME, Type.GetType(DS_FIELD_LAPS_START_TIME_TYPE));
			dtL.Columns.Add(DS_FIELD_LAPS_TOTAL_TIME, Type.GetType(DS_FIELD_LAPS_TOTAL_TIME_TYPE));
			dtL.Columns.Add(DS_FIELD_LAPS_TOTAL_DISTANCE, Type.GetType(DS_FIELD_LAPS_TOTAL_DISTANCE_TYPE));
			dtL.Columns.Add(DS_FIELD_LAPS_BEGIN_LATITUDE, Type.GetType(DS_FIELD_LAPS_BEGIN_LATITUDE_TYPE));
			dtL.Columns.Add(DS_FIELD_LAPS_END_LATITUDE , Type.GetType(DS_FIELD_LAPS_END_LATITUDE_TYPE));
			dtL.Columns.Add(DS_FIELD_LAPS_BEGIN_LONGITUDE, Type.GetType(DS_FIELD_LAPS_BEGIN_LONGITUDE_TYPE));
			dtL.Columns.Add(DS_FIELD_LAPS_END_LONGITUDE, Type.GetType(DS_FIELD_LAPS_END_LONGITUDEE_TYPE));
			dtL.Columns.Add(DS_FIELD_LAPS_CALORIES, Type.GetType(DS_FIELD_LAPS_CALORIES_TYPE));
			dtL.Columns.Add(DS_FIELD_LAPS_TRACK_INDEX, Type.GetType(DS_FIELD_LAPS_TRACK_INDEX_TYPE));
			//dtL.Columns.Add(DS_FIELD_LAPS_UNUSED_1, Type.GetType(DS_FIELD_LAPS_UNUSED_1_TYPE));

            dtL.Columns.Add(DS_FIELD_LAPS_INDEX, Type.GetType(DS_FIELD_LAPS_INDEX_TYPE));
            dtL.Columns.Add(DS_FIELD_LAPS_AVERAGE_HEART_RATE, Type.GetType(DS_FIELD_LAPS_AVERAGE_HEART_RATE_TIME_TYPE));
            dtL.Columns.Add(DS_FIELD_LAPS_MAX_HEART_RATE, Type.GetType(DS_FIELD_LAPS_MAX_HEART_RATE_TYPE));
            dtL.Columns.Add(DS_FIELD_LAPS_INTENSITY, Type.GetType(DS_FIELD_LAPS_INTENSITY_TIME_TYPE));
            dtL.Columns.Add(DS_FIELD_LAPS_AVERAGE_CADENCE, Type.GetType(DS_FIELD_LAPS_AVERAGE_CADENCE_TIME_TYPE));
            dtL.Columns.Add(DS_FIELD_LAPS_TRIGGER_METHOD, Type.GetType(DS_FIELD_LAPS_TRIGGER_METHOD_TIME_TYPE));
            dtL.Columns.Add(DS_FIELD_LAPS_MAX_SPEED, Type.GetType(DS_FIELD_LAPS_MAX_SPEED_TIME_TYPE));


			//add the data
			foreach(Lap objLap in mcLaps)
			{
				object[] objRow = new object[16];
				objRow[0] = objLap.StartTime;
				objRow[1] = objLap.TotalTime;
				objRow[2] = objLap.TotalDistance;
				objRow[3] = objLap.BeginLatitude;
				objRow[4] = objLap.EndLatitude;
				objRow[5] = objLap.BeginLongitude;
				objRow[6] = objLap.EndLongitude;
				objRow[7] = objLap.Calories;
				objRow[8] = objLap.TrackIndex;
                objRow[9] = objLap.Index;
                objRow[10] = objLap.AverageHeartRate;
                objRow[11] = objLap.MaxHeartRate;
                objRow[12] = objLap.Intensity;
                objRow[13] = objLap.AverageCadence;
                objRow[14] = objLap.TriggerMethod;
                objRow[15] = objLap.MaxSpeed;


				dtL.Rows.Add(objRow);
				
			}
			//tables populated so add the tables to the dataset
			ds.Tables.Add(dtL);

			return ds;
		}
        /// <summary>
        /// Overridden method. Returns true of the values of each
        /// of the properties are equal in value.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>boolean</returns>
        public override bool Equals(object obj)
		{
			try
			{
				LapCollection objLaps = null;

				//check the type first
				if(obj.GetType() != this.GetType() )
					return false;

				//type ok so cast
				objLaps = (LapCollection)obj;

				//if the number in each collection is different then exit
				int w1Count = mcLaps.Count;
				int w2Count = objLaps.Count;
				if(w1Count != w2Count)
					return false;

				//both with the same number of elements so chech each one in turn
				for( int index = 0; index < w1Count; index++ )
				{
					if( !objLaps[index].Equals(mcLaps[index]) )
						return false;
				}
			}
			catch
			{
				throw;
			}
			finally
			{}

			//if we got here then they must match
			return true;
		}
        /// <summary>
        /// Overridden function. Retrieves a value that indicates the hash code value for the object.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
		{
			//this value will be used for the overriden GetHashCode function and should
			//ensure that two object that are the same return the same Hash Code.
			//the hash code has to be imutable to is stored in a member variable.
			if( m_hashCode <= 0 )
				m_hashCode = this.ToXml().GetHashCode();
	
			return m_hashCode;
		}

	}
}
